import json
import os
import socket
import sys
import time
import zipfile

import requests


def get_local_ip():
    """
    获取本地ipv4地址
    """
    try:
        csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        csock.connect(('8.8.8.8', 80))
        (addr, port) = csock.getsockname()
        csock.close()
        return addr
    except socket.error:
        return "127.0.0.1"


class Config(object):
    # 服务器信息
    server_info = {
        "ip": get_local_ip(),
        "password": "hairou"
    }

    # ess url中path配置信息
    ess_url = {
        # 地图导出
        "map_export": "http://{ip}:19000/map/export".format(ip=server_info["ip"]),
        # 地图导入
        "model_loadMapJsonZip": "http://{ip}:19000/model/loadMapJsonZip".format(ip=server_info["ip"]),
        # 重启actor
        "model_restartController": "http://{ip}:19000/actor/restartController".format(ip=server_info["ip"]),
        # 查询actor
        "actor_query": "http://{ip}:19000/actor/query".format(ip=server_info["ip"])
    }

    server_ess_base_path = "/data/workspace/ess-p"

    # 日志打印等级，默认为1。1：debug + info + error；2：info + error；3：error；
    log_level = 2


class log(object):
    '''
    用于定义log日志打印的方法
    '''

    @classmethod
    def debug(cls, *args):
        if Config.log_level != 1:
            return
        # 脚本名称
        script_name = os.path.basename(sys._getframe().f_back.f_code.co_filename)
        # 函数名称
        fun_name = sys._getframe().f_back.f_code.co_name
        # 代码所在行数
        script_line = sys._getframe().f_back.f_lineno
        # 执行时间
        start_time = time.strftime("%Y-%m-%d_%H-%M-%S")
        # print("[%s][%s][%s] DEBUG %s\n" % (script_name, script_line, fun_name, start_time), *args)

    @classmethod
    def info(cls, *args):
        if Config.log_level > 2:
            return
        # 脚本名称
        script_name = os.path.basename(sys._getframe().f_back.f_code.co_filename)
        # 函数名称
        fun_name = sys._getframe().f_back.f_code.co_name
        # 代码所在行数
        script_line = sys._getframe().f_back.f_lineno
        # 执行时间
        start_time = time.strftime("%Y-%m-%d_%H-%M-%S")
        # print("[%s][%s][%s] INFO %s\n" % (script_name, script_line, fun_name, start_time), *args)

    @classmethod
    def error(cls, *args):
        # 脚本名称
        script_name = os.path.basename(sys._getframe().f_back.f_code.co_filename)
        # 函数名称
        fun_name = sys._getframe().f_back.f_code.co_name
        # 代码所在行数
        script_line = sys._getframe().f_back.f_lineno
        # 执行时间
        start_time = time.strftime("%Y-%m-%d_%H-%M-%S")
        # print("[%s][%s][%s] ERROR %s\n" % (script_name, script_line, fun_name, start_time), *args)


class Cmd(object):
    '''
    发送消息
    '''

    @staticmethod
    def send_get_request(url):
        '''
        发送http get请求
        :param url: 请求连接
        :return:响应结果
        '''
        # 请求头
        _headers = {
            "Accept": "*/*",
            "Content-Type": "application/json",
            "Cache-Control": "no-cache",
            "User-Agent": "Apache-HttpClient/4.5.6 (Java/1.8.0_152-release)",
        }
        log.debug("请求连接：\n", url)
        # 发送请求并获取响应结果
        result = requests.get(url, headers=_headers)
        log.debug("响应结果：\n", result)
        return result

    @staticmethod
    def send_post_request(url, data):
        '''
        发送http post请求
        :param url: 请求连接
        :param data: 请求参数（json格式）
        :return:响应结果
        '''
        # 请求头
        _headers = {
            "Accept": "*/*",
            "Content-Type": "application/json",
            "Cache-Control": "no-cache",
            "User-Agent": "Apache-HttpClient/4.5.6 (Java/1.8.0_152-release)",
        }
        log.debug("请求连接：\n", url)
        log.debug("请求参数：\n", json.dumps(data, indent=4, separators=(', ', ': '), ensure_ascii=False))
        # 发送请求并获取响应结果
        try:
            result = requests.post(url, json=data, headers=_headers)
        except Exception as errorMsg:
            response = {"code": 400, "errMsg": errorMsg}
            return response
        log.debug("响应结果：\n", result.text)
        return json.loads(result.text)

    @staticmethod
    def send_linux_cmd(cmd, sendMsg=None):
        log.debug("发送指令：\n", cmd)
        if sendMsg:
            result = os.system("echo {sendMsg} | sudo -S {cmd}".format(sendMsg=sendMsg, cmd=cmd))
        else:
            result = os.system(cmd)
        return result


class CleanupESS(object):
    def __init__(self):
        self.unzip_filename = "unzip.zip"
        self.unzip_filename_path = "{path}/{filename}".format(path=Config.server_ess_base_path,
                                                              filename=self.unzip_filename)
        self.zip_filename = "zip.zip"
        self.zip_filename_path = "{path}/{filename}".format(path=Config.server_ess_base_path,
                                                            filename=self.zip_filename)
        self.zip_map_filename = "map"
        self.zip_map_filename_path = "{path}/{filename}".format(path=Config.server_ess_base_path,
                                                                filename=self.zip_map_filename)
        self.map_data = {}

        self.unzip_file()
        self.cleanup_data()
        self.zip_file()
        self.update_data()

    def unzip_file(self):
        log.info("开始读取数据...")
        result = Cmd.send_get_request(url=Config.ess_url["map_export"])
        if result.status_code == 200:
            with open(self.unzip_filename_path, 'wb') as f:
                f.write(result.content)
        unzip_file = zipfile.ZipFile(self.unzip_filename_path, "r")
        content = unzip_file.read(unzip_file.namelist()[0])
        self.map_data = json.loads(content)
        log.info("读取数据完毕")

    def cleanup_data(self):
        log.info("开始清理数据...")
        self.map_data["container"] = []
        self.map_data["transportTask"] = []
        self.map_data["wmsTask"] = []
        for location in self.map_data["location"]:
            if "containerCode" in location.keys():
                location.pop("containerCode")
        for robot in self.map_data["robot"]:
            for key in list(robot.keys()):
                if key == "errCmdDetail":
                    robot[key] = {}
                elif key == "unfinishedTransportTaskCode":
                    robot.pop(key)
                elif key == "assignedTransportTaskCode":
                    robot.pop(key)
                elif key == "trayLoadingContainerCode":
                    robot.pop(key)
        self.map_data = json.dumps(self.map_data, indent=4, separators=(', ', ': '), ensure_ascii=False)

        cmd = "rm %s" % self.unzip_filename_path
        Cmd.send_linux_cmd(cmd=cmd, sendMsg=Config.server_info["password"])
        log.info("清理数据完毕")

    def zip_file(self):
        log.info("开始打包数据...")
        with open(self.zip_map_filename_path, "w") as f:
            f.writelines(self.map_data)

        zip_file = zipfile.ZipFile(self.zip_filename_path, "w")
        zip_file.write(self.zip_map_filename_path)
        zip_file.close()

        cmd = "rm %s" % self.zip_map_filename_path
        Cmd.send_linux_cmd(cmd=cmd, sendMsg=Config.server_info["password"])

        cmd = "mv %s /data/workspace/ess-p/ess-gateway/map/" % self.zip_filename_path
        Cmd.send_linux_cmd(cmd=cmd, sendMsg=Config.server_info["password"])
        log.info("打包数据完毕")

    def update_data(self):
        log.info("开始更新数据...")

        ess_gateway_path = "{base_path}/ess-gateway".format(base_path=Config.server_ess_base_path)
        cmd = "cd {ess_gateway_path} && docker-compose down".format(ess_gateway_path=ess_gateway_path)
        Cmd.send_linux_cmd(cmd=cmd)

        cmd = "rm -rf /data/workspace/ess-p/ess-gateway/data/ess-model/*"
        Cmd.send_linux_cmd(cmd=cmd, sendMsg=Config.server_info["password"])
        cmd = "rm -rf /data/workspace/ess-p/ess-gateway/logs/*"
        Cmd.send_linux_cmd(cmd=cmd, sendMsg=Config.server_info["password"])

        cmd = "redis-cli flushall"
        Cmd.send_linux_cmd(cmd=cmd, sendMsg=Config.server_info["password"])

        cmd = "cd {ess_gateway_path} && docker-compose up -d".format(ess_gateway_path=ess_gateway_path)
        Cmd.send_linux_cmd(cmd=cmd)

        while True:
            cmd = 'curl -X GET "%s" -H  "accept: application/json" >> /dev/null 2>&1' % Config.ess_url["actor_query"]
            if Cmd.send_linux_cmd(cmd=cmd) == 0:
                log.debug("ess-gateway启动完毕")
                break
            else:
                log.debug("ess-gateway启动中...")
                time.sleep(5)

        data = {
            "mapJsonZipFileName": "/hairou/map/%s" % self.zip_filename
        }
        Cmd.send_post_request(url=Config.ess_url["model_loadMapJsonZip"], data=data)

        cmd = "rm /data/workspace/ess-p/ess-gateway/map/%s" % self.zip_filename
        Cmd.send_linux_cmd(cmd=cmd, sendMsg=Config.server_info["password"])

        Cmd.send_post_request(url=Config.ess_url["model_restartController"], data=None)

        log.info("更新数据完毕")


if __name__ == "__main__":
    CleanupESS()
